package cn.itsource.config;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.itsource.basic.annotation.CustomeParam;
import com.alibaba.fastjson.JSONObject;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ValueConstants;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

@Slf4j
@AllArgsConstructor
@NoArgsConstructor
public class CustomMethodArgumentResolver implements HandlerMethodArgumentResolver {

    private static final String POST = "post";
    private static final String APPLICATION_JSON = "application/json";
    /**
     * 解析Content-Type为application/json的默认解析器是RequestResponseBodyMethodProcessor
     */
    private RequestResponseBodyMethodProcessor requestResponseBodyMethodProcessor;
    /**
     * 判断是否需要处理该参数
     *
     * @param parameter the method parameter to check
     * @return {@code true} if this resolver supports the supplied parameter;
     * {@code false} otherwise
     */
    @Override
    public boolean supportsParameter (MethodParameter parameter) {
        // 处理带有@CustomeParam注解的参数
        //处理@requestbody 参数去前后中间空格的业务
         if(parameter.hasParameterAnnotation (CustomeParam.class)|| parameter.hasParameterAnnotation (RequestBody.class)) return true;

        return false;
    }

    @Override
    public Object resolveArgument (MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        HttpServletRequest servletRequest = webRequest.getNativeRequest (HttpServletRequest.class);

        String contentType = Objects.requireNonNull (servletRequest).getContentType ();

        if (contentType == null || !contentType.contains (APPLICATION_JSON)) {
            log.error ("解析参数异常，contentType需为{}", APPLICATION_JSON);
            throw new RuntimeException ("解析参数异常，contentType需为application/json");
        }

        if (!POST.equalsIgnoreCase (servletRequest.getMethod ())) {
            log.error ("解析参数异常，请求类型必须为post");
            throw new RuntimeException ("解析参数异常，请求类型必须为post");
        }
        if (parameter.hasParameterAnnotation (RequestBody.class)){

            //调用源码数据解析器
            return requestResponseBodyMethodProcessor.resolveArgument(parameter,
                    mavContainer, webRequest, binderFactory);
        }
        return bindRequestParams (parameter, servletRequest);
    }

    private Object bindRequestParams (MethodParameter parameter, HttpServletRequest servletRequest) {
        Class<?> parameterType = parameter.getParameterType ();
        String requestBody = this.getRequestBody (servletRequest);
        JSONObject jsonObject = JSONObject.parseObject (requestBody);
            CustomeParam customParam = parameter.getParameterAnnotation (CustomeParam.class);


            Map<String, Object> params = jsonObject.getInnerMap ();

            params = MapUtil.isEmpty (params) ? new HashMap<> (0) : params;
            String name = StrUtil.isBlank (customParam.value ()) ? parameter.getParameterName () : customParam.value ();
            Object value = params.get (name);

            if (parameterType.equals (String.class)) {
                if (StrUtil.isBlank ((String) value)) {
                    log.error ("参数解析异常,String类型参数不能为空");
                    throw new RuntimeException ("参数解析异常,String类型参数不能为空");
                }
            }

            if (customParam.required ()) {
                if (value == null) {
                    log.error ("参数解析异常,require=true,值不能为空");
                    throw new RuntimeException ("参数解析异常,require=true,值不能为空");
                }
            } else {
                if (customParam.defaultValue ().equals (ValueConstants.DEFAULT_NONE)) {
                    log.error ("参数解析异常,require=false,必须指定默认值");
                    throw new RuntimeException ("参数解析异常,require=false,必须指定默认值");
                }
                if (value == null) {
                    value = customParam.defaultValue ();
                }
            }

            return Convert.convert(parameterType,value);

    }

    /**
     * 通过request 去获取body数据
     * @param servletRequest
     * @return
     */
    public static String getRequestBody (HttpServletRequest servletRequest) {
        StringBuilder stringBuilder = new StringBuilder ();
        try {
            BufferedReader reader = servletRequest.getReader ();
            char[] buf = new char[1024];
            int length;
            while ((length = reader.read (buf)) != -1) {
                stringBuilder.append (buf, 0, length);
            }
        } catch (IOException e) {
            throw new RuntimeException ("读取流异常");
        }
        return stringBuilder.toString ();
    }
}